import json
import os
import uuid
from datetime import datetime

import jieba
import redis
import requests
from openai import OpenAI
from rest_framework.exceptions import AuthenticationFailed
from django.http import StreamingHttpResponse
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt
from rest_framework.permissions import AllowAny
from rest_framework.authentication import BaseAuthentication

from rest_framework.response import Response
from rest_framework.views import APIView

from boss import settings
from ai_resume_generator.generate_resume_test import generate_word_resume, generate_resume_by_llm
from user.models import User, JobInfo, WorkExperience
from utils.JWTTool import JwtUtils

import logging

logger = logging.getLogger(__name__)

# Create your views here.

client = redis.Redis(host="localhost", port=6379, db=10, decode_responses=True, encoding='utf-8')


def safe_encode_error_message(error_msg):
    """
    安全编码错误信息，避免Unicode字符导致的编码问题
    """
    try:
        if isinstance(error_msg, str):
            # 确保字符串是UTF-8编码
            return error_msg.encode('utf-8', errors='ignore').decode('utf-8')
        else:
            # 如果不是字符串，先转换为字符串
            str_msg = str(error_msg)
            return str_msg.encode('utf-8', errors='ignore').decode('utf-8')
    except (UnicodeError, UnicodeEncodeError, UnicodeDecodeError):
        return "系统内部错误"


# 学历查询相关函数（从xueli.py集成）
def verify_education(arguments):
    """
    验证学历的工具(梦远数据的API)
    """
    try:
        # 直接使用API密钥，不依赖环境变量
        api_key = "Ii875XV8f7BomLGhgg1obwMD1Whbcr"

        print(f"使用API密钥: {api_key[:10]}...")

        # 设置url
        url = 'https://www.apimy.cn/api/xxw/bgcx?key=' + api_key
        vcode = arguments["vcode"]

        print(f"正在查询学历编码: {vcode}")
        print(f"API URL: {url}")

        # 发送post请求
        response = requests.post(url, data={'vcode': vcode}, timeout=10)

        # 检查响应状态
        if response.status_code != 200:
            print(f"HTTP请求失败，状态码: {response.status_code}")
            return f"学历验证失败: HTTP请求失败，状态码 {response.status_code}"

        # 获取响应内容
        result = response.json()

        # 打印结果
        print("API响应结果:")
        print(result)
        print(f"响应类型: {type(result)}")

        if result.get("code") == 200:
            return json.dumps(result["data"], ensure_ascii=False)
        else:
            return f"学历验证失败: {result.get('msg', '未知错误')}"

    except requests.exceptions.Timeout:
        print("请求超时")
        return "学历验证失败: 请求超时"
    except requests.exceptions.RequestException as e:
        print(f"网络请求错误: {e}")
        return f"学历验证失败: 网络请求错误 - {str(e)}"
    except json.JSONDecodeError as e:
        print(f"JSON解析错误: {e}")
        return f"学历验证失败: JSON解析错误 - {str(e)}"
    except Exception as e:
        print(f"学历验证失败: {e}")
        return f"学历验证失败: {str(e)}"


# 学历查询工具列表
education_tools = [
    {
        "type": "function",
        "function": {
            "name": "verify_education",
            "description": "通过学信网验证码查询并验证学历信息, 包括:姓名, 学校,专业等详细内容",
            "parameters": {
                "type": "object",
                "properties": {
                    "vcode": {
                        "type": "string",
                        "description": "学信网验证码"
                    }
                },
                "required": ["vcode"]
            }
        }
    }
]

# 通义千问客户端
qwen_client = OpenAI(
    api_key="sk-2c036d80d14a443f8769e072bb09a2e1",
    base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
)


def get_ai_response_with_tools(messages):
    """
    使用工具调用获取AI响应
    """
    completion = qwen_client.chat.completions.create(
        model="qwen-plus",
        messages=messages,
        tools=education_tools,
    )
    return completion


def process_education_query_with_ai(user_input):
    """
    使用AI工具调用处理学历查询
    """
    try:
        messages = [{"role": "user", "content": user_input}]
        completion = get_ai_response_with_tools(messages)

        assistant_output = completion.choices[0].message
        tool_calls = completion.choices[0].message.tool_calls

        messages.append(assistant_output)

        if assistant_output.content == "" and tool_calls is not None:
            # 处理function calling
            print("需要处理function calling...")
            for tool_call in tool_calls:
                tool_call_id = tool_call.id
                func_name = tool_call.function.name
                func_arguments = tool_call.function.arguments
                arguments = json.loads(func_arguments)
                print(f"正在调用工具 [{func_name}]，参数：{arguments}")

                if func_name == "verify_education":
                    tool_result = verify_education(arguments)
                    print(f"工具返回结果:{tool_result}")

                    # 构造工具返回信息
                    tool_message = {
                        "role": "tool",
                        "tool_call_id": tool_call_id,
                        "content": tool_result,
                    }
                    messages.append(tool_message)

                    # 第二次调用大模型获取最终答案
                    completion = get_ai_response_with_tools(messages)
                    final_answer = completion.choices[0].message.content
                    print(f"最终的答案:{final_answer}")
                    return final_answer
                else:
                    return "不支持的函数"
        else:
            return assistant_output.content

    except Exception as e:
        print(f"AI处理学历查询失败: {e}")
        error_msg = safe_encode_error_message(e)
        return f"学历查询处理失败: {error_msg}"


def is_education_query_intent(question):
    """
    判断是否为学历查询意图
    """
    education_keywords = [
        "学历", "学信网", "学历验证", "学历查询", "学历信息",
        "毕业证", "学位证", "学历认证", "教育背景", "学历编号"
    ]

    question_lower = question.lower()
    for keyword in education_keywords:
        if keyword in question_lower:
            return True
    return False


def extract_education_number_from_text(text):
    """
    从文本中提取学历编号
    """
    import re

    # 匹配10-20位数字或字母数字组合
    patterns = [
        r'[A-Z0-9]{10,20}',  # 大写字母和数字组合
        r'[a-z0-9]{10,20}',  # 小写字母和数字组合
        r'\d{10,20}',  # 纯数字
    ]

    for pattern in patterns:
        matches = re.findall(pattern, text)
        if matches:
            return matches[0]  # 返回第一个匹配的编号

    return None


class NoAuthentication(BaseAuthentication):
    """禁用DRF认证的认证类"""

    def authenticate(self, request):
        return None


def get_user_id(request):
    # 从Authorization header中获取token并解析用户ID
    auth_header = request.META.get('HTTP_AUTHORIZATION', '')
    print("传递的token:", auth_header)

    # 如果没有提供认证头，返回默认用户ID（用于测试）
    if not auth_header:
        print("未提供认证Token，使用默认用户ID")
        return 999999

    if not auth_header.startswith('Bearer '):
        print("Token格式错误，使用默认用户ID")
        return 999999

    token = auth_header.split(' ')[1]
    if not token:
        print("Token为空，使用默认用户ID")
        return 999999

    print("解析的token:", token)

    try:
        userid = JwtUtils.get_user_id_from_token(token)
        print("解析的userid:", userid)
        return userid
    except AuthenticationFailed as e:
        print(f"Token验证失败: {str(e)}，使用默认用户ID")
        return 999999
    except Exception as e:
        print(f"未知错误: {str(e)}，使用默认用户ID")
        return 999999


def create_session(userid):
    """
    创建新会话的通用函数
    """
    # 生成唯一的sessionid
    session_id = str(uuid.uuid4())
    # 初始化hash结构,会话元数据 session:{userId}:{seesionid}-->创建时间,空的最后的消息
    session_meta = {
        "session_id": session_id,
        "create_time": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
        "last_message": "",  # 最后一条消息,空的
    }
    # 保存会话元数据: 命名规则: 项目名:业务名:功能名:业务数据
    session_key = f"boss:chat:session:{userid}:{session_id}"
    # 使用hmset替代hset with mapping参数
    client.hmset(session_key, session_meta)

    # 初始化空的消息列表(List):message:u1:s1
    message_list_key = f"boss:chat:message:list:{userid}:{session_id}"

    init_system_message = {"role": "system", "content": "你是专业的人力资源专家"}
    # 添加消息到列表左侧
    # 将字典转化成字符串 序列化
    client.lpush(message_list_key, json.dumps(init_system_message, ensure_ascii=False))
    # 将sessionid添加到用户的会话集合(Set结构)
    session_set_key = f"boss:chat:session:set:{userid}"
    client.sadd(session_set_key, session_id)
    # 为所有的键设置过期时间(30天)
    client.expire(session_key, 60 * 60 * 24 * 30)
    client.expire(message_list_key, 60 * 60 * 24 * 30)
    client.expire(session_set_key, 60 * 60 * 24 * 30)

    return session_id, session_meta


@method_decorator(csrf_exempt, name='dispatch')
class CreateSessionAPIView(APIView):
    """
    创建会话的接口
    """
    authentication_classes = [NoAuthentication]
    permission_classes = [AllowAny]

    def post(self, request):
        try:
            # 从Authorization header中获取token并解析用户ID
            userid = get_user_id(request)

            session_id, session_meta = create_session(userid)

            return Response({
                "code": 1,
                "message": "创建会话成功",
                "data": {
                    "session_id": session_id
                }

            })

        except Exception as e:
            print(e)
            return Response({
                "code": 0,
                "message": f"创建会话失败:{str(e)}"
            })


@method_decorator(csrf_exempt, name='dispatch')
class ListSessionAPIView(APIView):
    authentication_classes = [NoAuthentication]
    permission_classes = [AllowAny]

    def get(self, request):
        try:
            # token = request.META.get('AUTHORIZATION')
            # userid = JwtUtils.get_user_id_from_token(token)
            # 1: 获取userid
            # userid = request.query_params.get('userid')
            userid = get_user_id(request)
            # 2: 从set结构获取该用户所有的session_id
            session_set_key = f"boss:chat:session:set:{userid}"
            session_ids = client.smembers(session_set_key)
            print(f"从redis里面获取到的会话ID集合:{session_ids}")
            sessions = []
            for session_id in session_ids:
                session_key = f"boss:chat:session:{userid}:{session_id}"
                session_meta = client.hgetall(session_key)
                sessions.append(session_meta)
            # 3: 对会话列表进行排序,按照创建时间倒序
            sessions.sort(key=lambda x: x['create_time'], reverse=True)
            return Response({
                "code": 1,
                "message": "获取会话列表成功",
                "data": {
                    "sessions": sessions
                }
            })
        except Exception as e:
            print(e)
            error_msg = safe_encode_error_message(e)
            return Response({
                "code": 0,
                "message": f"获取会话列表失败:{error_msg}"
            })


@method_decorator(csrf_exempt, name='dispatch')
class SessionMessageAPIView(APIView):
    authentication_classes = [NoAuthentication]
    permission_classes = [AllowAny]
    """
    1:获取userid
    2:获取session_id
    3:验证session_id是否存在[通过hash结构验证]
    4:从list结构读取所有的消息
    5:返回的所有的消息
    """

    def get(self, request):
        try:
            # userid = request.query_params.get('userid')
            userid = get_user_id(request)
            session_id = request.query_params.get('session_id')

            session_key = f"boss:chat:session:{userid}:{session_id}"
            session_meta = client.hgetall(session_key)
            if not session_meta:
                return Response({
                    "code": 0,
                    "message": "会话不存在"
                })

            message_list_key = f"boss:chat:message:list:{userid}:{session_id}"
            # 反序列化: 将字符串转化成字典，处理编码问题
            messages = []
            for msg in client.lrange(message_list_key, 0, -1):
                try:
                    # 确保消息使用UTF-8编码
                    if isinstance(msg, bytes):
                        msg = msg.decode('utf-8', errors='ignore')
                    elif isinstance(msg, str):
                        # 如果已经是字符串，确保它是UTF-8编码
                        msg = msg.encode('utf-8', errors='ignore').decode('utf-8')
                    messages.append(json.loads(msg))
                except (json.JSONDecodeError, UnicodeDecodeError) as e:
                    print(f"消息解析失败: {e}, 消息内容: {msg}")
                    # 跳过有问题的消息
                    continue
            messages.reverse()
            print(f"用户ID:{userid},会话ID:{session_id},消息列表:{messages}")
            return Response({
                "code": 1,
                "message": "获取消息列表成功",
                "data": {
                    "messages": messages[1:]
                }
            })
        except Exception as e:
            print(e)
            error_msg = safe_encode_error_message(e)
            return Response({
                "code": 0,
                "message": f"获取消息列表失败:{error_msg}"
            })


ai_client = OpenAI(
    api_key="sk-860cb64d28c848bbbcba0ca67b991413",
    base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
)


def intent_recognition(question: str) -> str:
    # 判断意图: 是否   --》是生成简历
    # 使用正确的词典文件路径
    dict_path = os.path.join(os.path.dirname(__file__), "boss_zhipin_dict.txt")
    if os.path.exists(dict_path):
        jieba.load_userdict(dict_path)
    else:
        print(f"警告: 词典文件不存在: {dict_path}")
    question_keyword_list = list(jieba.cut(question))
    print(f"原始问题分词:{question_keyword_list}")

    generate_resume_word = ["简历", "简历生成", "生成简历", "导出简历", "下载简历", "生成一份简历"]
    for question_keyword in question_keyword_list:
        if question_keyword in generate_resume_word:
            logger.info("生成简历的意图----------------")
            return "generate_resume"

    # 检查是否为岗位推荐意图
    job_recommend_words = ["岗位推荐", "职位推荐", "工作推荐", "智能推荐", "推荐岗位", "推荐职位", "匹配岗位"]
    for question_keyword in question_keyword_list:
        if question_keyword in job_recommend_words:
            logger.info("岗位推荐的意图----------------")
            return "job_recommend"

    return "other"


def generate_resume_prompt(user_id: int) -> str:
    try:
        # 获取用户基本信息
        user = User.objects.get(id=user_id)
        user_phone = user.phone or "未填写"
        user_email = user.email or "未填写"
        logging.info(f"用户ID:{user_id},用户手机号:{user_phone},用户邮箱:{user_email}")

        # 学历字典
        education_dict = {
            1: '初中及以下',
            2: '高中',
            3: '中专',
            4: '大专',
            5: '本科',
            6: '硕士',
            7: '博士',
            8: '博士及以上'
        }

        # 当前状态字典
        current_status_dict = {
            1: '在职看机会',
            2: '离职',
            3: '在校生等',
            4: '兼职'
        }

        # 行业字典
        industry_dict = {
            1: '互联网',
            2: '电子商务',
            3: '金融',
            4: '教育',
            5: '医疗',
            6: '文娱',
            7: '游戏',
            8: '生活服务',
            9: '物流',
            10: '社交',
            11: '旅游',
            12: '工具',
            13: '汽车',
            14: '物联网',
            15: '信息安全',
            16: '人工智能',
            17: '区块链',
            18: '企业服务',
            19: '新零售',
            20: '智能制造',
            21: '其他'
        }

        # 获取用户求职信息
        jobinfo = JobInfo.objects.filter(user=user).first()
        if not jobinfo:
            return "用户尚未填写求职信息"

        joninfo_name = jobinfo.name or "未填写"
        jobinfo_sex = "女" if jobinfo.sex == 1 else "男"
        joninfo_birthdate = jobinfo.birthdate or "未填写"
        joinfo_description = jobinfo.description or "未填写"
        joninfo_education = education_dict.get(jobinfo.education, "未填写")
        joninfo_current_status = current_status_dict.get(jobinfo.current_status, "未填写")

        # 获取工作经历
        workexperience_list = WorkExperience.objects.filter(job_info=jobinfo)
        workexperiences = []
        for workexperience in workexperience_list:
            workexperience_dict = {
                "company": workexperience.company or "未填写",
                "position": workexperience.position or "未填写",
                "start_date": workexperience.start_date or "未填写",
                "end_date": workexperience.end_date or "未填写",
                "industry": industry_dict.get(workexperience.industry, "未填写"),
                "salary_range": workexperience.salary_range or "未填写",
                "description": workexperience.description or "未填写",
                "is_current": workexperience.is_current
            }
            workexperiences.append(workexperience_dict)

        # 构建用户信息摘要
        user_data_summary = f"""
    ## 用户真实信息
    姓名: {joninfo_name}
    性别: {jobinfo_sex}
    联系电话: {user_phone}
    邮箱: {user_email}
    出生日期: {joninfo_birthdate}
    学历: {joninfo_education}
    当前状态: {joninfo_current_status}
    个人简介: {joinfo_description}

    ## 工作经历信息
    """

        if workexperiences:
            for i, exp in enumerate(workexperiences, 1):
                user_data_summary += f"""
    工作经历{i}:
    - 公司: {exp['company']}
    - 职位: {exp['position']}
    - 开始时间: {exp['start_date']}
    - 结束时间: {exp['end_date']}
    - 行业: {exp['industry']}
    - 薪资范围: {exp['salary_range']}
    - 工作描述: {exp['description']}
    - 是否当前工作: {'是' if exp['is_current'] else '否'}
    """
        else:
            user_data_summary += "暂无工作经历信息"

        prompt = f"""
    ## 设定角色
    你是专业的简历优化专家，擅长根据用户的真实信息生成专业、有针对性的简历。

    ## 任务描述
    请根据以下用户的真实信息，生成一份专业的简历。要求：
    1. 必须使用用户提供的真实信息，不得编造或虚构
    2. 对于"未填写"的信息，可以合理推测或建议用户补充
    3. 基于用户的工作经历和技能，推荐合适的求职方向
    4. 优化表达方式，让简历更加专业和有吸引力

    {user_data_summary}

    ## 输出格式
    请严格按照以下JSON格式输出，不要添加任何其他内容：
    {{
        "base_info": {{
            "name": "{joninfo_name}",
            "sex": "{jobinfo_sex}",
            "phone": "{user_phone}",
            "email": "{user_email}",
            "birth_date": "{joninfo_birthdate}",
            "education": "{joninfo_education}",
            "current_status": "{joninfo_current_status}",
            "self_intro": "{joinfo_description}",
            "job_objective": "基于用户经历推荐的求职方向"
        }},
        "work_experience": {workexperiences},
        "project_experience": [
            {{
                "project_name": "基于用户工作经历推荐的项目名称",
                "time": "项目时间",
                "description": "项目描述",
                "technology_stack": "技术栈",
                "responsibility": "个人职责"
            }}
        ],
        "skills": {{
            "technical_skills": "基于工作经历提取的技术技能",
            "soft_skills": "软技能",
            "tools": "使用的工具"
        }},
        "self_evaluation": "基于真实经历的个人评价"
    }}
    """
        return prompt
    except Exception as e:
        error_msg = safe_encode_error_message(e)
        logger.error(f"生成简历提示词时出错: {error_msg}")
        return f"生成简历提示词时出错: {error_msg}"


def compress_message_history(messages):
    """
    messages:所有的消息 12
    """
    prompt = """
    请将以下历史对话压缩为简洁的摘要，保留关键信息和上下文逻辑，供继续对话使用。
    不需要逐句总结，重点提取讨论的主题、关键问题和重要结论。
    压缩后的内容控制在200字以内。
    历史对话:
    """
    print(f"所有的消息:{messages}")
    print(f"所有的消息长度:{len(messages)}")
    if len(messages) <= 10:
        return messages
    # 保留最近的10条消息[滑动窗口] 10
    recent_message = messages[-10:]

    # 需要压缩历史消息,第一条是系统消息 2
    early_message = messages[1:-10]
    print(f"需要压缩的历史消息:{early_message}")
    history_text = ""
    for message in early_message:
        # user/system/assistant
        role = message["role"]
        content = message["content"]
        role_name = "用户" if role == "user" else "模型助手"
        history_text += "\n".join([f"{role_name}: {content}"])

    prompt += history_text

    print(f"最后完整的提示词:{prompt}")
    result = ai_client.chat.completions.create(
        model="qwen-plus",
        messages=[
            {
                "role": "user",
                "content": prompt
            }
        ],
        max_tokens=1024,
        temperature=0.6,
    )
    # 返回结果
    content = result.choices[0].message.content
    print(f"大模型压缩后的结果:{content}")
    # 压缩消息
    compress_message = [{"role": "system", "content": content}]
    return compress_message + recent_message


def Fenchi(question):
    # 新增外部词典load_userdict
    userdict = os.path.join(os.path.dirname(__file__), "boss_zhipin_dict.txt")
    if os.path.exists(userdict):
        jieba.load_userdict(userdict)
    else:
        print(f"警告: 词典文件不存在: {userdict}")
    result = list(jieba.cut(question))
    result = normalize_tokens(result)
    targetArr = ['简历', '生成简历', '简历生成', '下载简历']
    # 如果命中了返回True没有命中返回False
    flag = any(item in result for item in targetArr)
    return flag


# 去除没有意义的词和同义词转化
def normalize_tokens(tokens):
    STOPWORDS = {"的", "了", "啊", "呢", "吗", "请", "帮我", "一下", "一下下", "我", ","}
    SYNONYM_MAP = {
        "生成简历": {"生成简历", "写简历", "做简历", "导出简历", "简历生成", "生成resume", "写CV"},
        "下载": {"下载", "导出", "保存", "保存为"}
    }
    # 去停用词
    tokens = [t for t in tokens if t.strip() and t not in STOPWORDS]
    # 同义词归一化
    norm = []
    for t in tokens:
        mapped = None
        for base, syns in SYNONYM_MAP.items():
            if t in syns:
                mapped = base
                break
        norm.append(mapped or t)
    return norm


def is_education_query_intent(question: str) -> bool:
    """
    判断是否为学历查询意图
    """
    education_keywords = [
        "学历", "验证", "学历编码", "学信网", "毕业证", "学位证",
        "学历查询", "学历验证", "验证学历", "查询学历", "学历编号"
    ]

    # 使用jieba分词
    question_keyword_list = list(jieba.cut(question))
    print(f"学历查询意图识别分词结果: {question_keyword_list}")

    # 检查是否包含学历相关关键词
    for keyword in education_keywords:
        if keyword in question:
            print(f"检测到学历查询意图，关键词: {keyword}")
            return True

    # 检查是否包含学历编码格式（10-20位字母数字组合）
    import re
    education_code_pattern = r'[A-Za-z0-9]{10,20}'
    if re.search(education_code_pattern, question):
        print("检测到学历编码格式，判断为学历查询意图")
        return True

    return False


def extract_education_number_from_text(text: str) -> str:
    """
    从文本中提取学历编号
    """
    import re

    # 匹配10-20位字母数字组合
    education_code_pattern = r'[A-Za-z0-9]{10,20}'
    matches = re.findall(education_code_pattern, text)

    if matches:
        # 返回第一个匹配的编码
        education_code = matches[0]
        print(f"提取到学历编码: {education_code}")
        return education_code

    print("未找到有效的学历编码")
    return None


@method_decorator(csrf_exempt, name='dispatch')
class ChatAPIView(APIView):
    authentication_classes = [NoAuthentication]
    permission_classes = [AllowAny]

    def post(self, request):
        question = request.data.get('question')
        # userid = request.data.get('userid')
        userid = get_user_id(request)
        session_id = request.data.get('session_id')
        try:
            if not question:
                return Response({
                    "code": 0,
                    "message": "问题不能为空"
                })

            session_key = f"boss:chat:session:{userid}:{session_id}"
            session_meta = client.hgetall(session_key)
            if not session_meta:
                # 重新执行CreateSessionAPIView
                session_id, session_meta = create_session(userid)

            # 4: 把当前的问题, 作为用户的消息存到redis
            #  的list消息列表中
            # 4.1:初始化空的消息列表(List):message:u1:s1
            intent_recognition_res = intent_recognition(question)
            message_list_key = f"boss:chat:message:list:{userid}:{session_id}"
            user_message = {"role": "user", "content": question}
            # 4.2 添加消息到列表左侧
            client.lpush(message_list_key, json.dumps(user_message, ensure_ascii=False))

            # 检查是否为学历查询意图
            if is_education_query_intent(question):
                education_number = extract_education_number_from_text(question)

                if education_number:
                    # 使用AI工具调用处理学历查询
                    ai_reply = process_education_query_with_ai(question)
                else:
                    ai_reply = "我检测到您想要查询学历信息，但没有找到有效的学历编号。\n\n请提供10-20位数字或字母数字组合的学历编号，例如：A7FKKV3C4Q40RWGD\n\n我会帮您查询对应的学历信息。"

                # 保存AI回复到Redis
                ai_message = {"role": "assistant", "content": ai_reply}
                client.lpush(message_list_key, json.dumps(ai_message, ensure_ascii=False))

                # 更新会话信息
                session_key = f"boss:chat:session:{userid}:{session_id}"
                client.hset(session_key, "last_message", ai_reply[:20])
                client.hset(session_key, "create_time", datetime.now().strftime("%Y-%m-%d %H:%M:%S"))

                # 获取最新消息列表，处理编码问题
                new_messages = []
                for msg in client.lrange(message_list_key, 0, -1):
                    try:
                        if isinstance(msg, bytes):
                            msg = msg.decode('utf-8', errors='ignore')
                        elif isinstance(msg, str):
                            # 如果已经是字符串，确保它是UTF-8编码
                            msg = msg.encode('utf-8', errors='ignore').decode('utf-8')
                        new_messages.append(json.loads(msg))
                    except (json.JSONDecodeError, UnicodeDecodeError):
                        continue
                new_messages.reverse()

                return Response({
                    "code": 1,
                    "message": "学历查询成功",
                    "data": {
                        "reply": ai_reply,
                        "messages": new_messages[1:],
                        "session_id": session_id,
                        "education_query": True
                    }
                })

            if intent_recognition_res == "generate_resume":
                # 组装生成简历的prompt
                question = generate_resume_prompt(userid)
            elif intent_recognition_res == "job_recommend":
                # 处理岗位推荐请求
                try:
                    # 获取用户信息
                    user = User.objects.get(id=userid)
                    jobinfo = JobInfo.objects.filter(user=user).first()
                    
                    if not jobinfo:
                        ai_reply = "请先完善您的求职信息，包括技能、工作经历等，这样我才能为您推荐合适的岗位。"
                    else:
                        # 构建用户技能和经验描述
                        user_skills = []
                        if jobinfo.description:
                            user_skills.append(jobinfo.description)
                        
                        # 获取工作经历
                        work_experiences = WorkExperience.objects.filter(job_info=jobinfo)
                        experience_text = ""
                        for exp in work_experiences:
                            experience_text += f"在{exp.company}担任{exp.position}，{exp.description or '负责相关工作'}；"
                        
                        # 使用真实的职位推荐系统
                        from rag.job_recommend.job_recommend_rag import hybrid_search_jobs
                        from rag.views import _generate_reasons_qwen
                        
                        # 构建查询文本
                        query_text = f"""
                        求职意向：Python后端工程师
                        技能：{jobinfo.description or '未填写'}
                        工作经历：{experience_text or '无工作经历'}
                        学历：{jobinfo.education or '未填写'}
                        """
                        
                        # 使用混合搜索获取真实职位
                        items = hybrid_search_jobs(query=query_text, top_k=5)
                        
                        if items:
                            # 生成推荐理由
                            try:
                                reasons = _generate_reasons_qwen(items, query_text)
                                for i, item in enumerate(items):
                                    item["reason"] = reasons[i] if i < len(reasons) else "技术栈匹配度高，符合岗位要求"
                            except Exception as e:
                                logger.error(f"生成推荐理由失败: {str(e)}")
                                for item in items:
                                    item["reason"] = "技术栈匹配度高，符合岗位要求"
                            
                            # 格式化推荐结果
                            ai_reply = "推荐岗位：\n"
                            for i, item in enumerate(items, 1):
                                ai_reply += f"{i}. {item['title']} - {item['company']} ({item['city']})\n"
                                ai_reply += f"   推荐理由：{item['reason']}\n\n"
                        else:
                            ai_reply = "抱歉，暂时没有找到匹配的岗位，请稍后重试。"
                        
                except Exception as e:
                    logger.error(f"岗位推荐失败: {str(e)}")
                    ai_reply = "岗位推荐功能暂时不可用，请稍后重试。"
                
                # 保存AI回复到Redis
                ai_message = {"role": "assistant", "content": ai_reply}
                client.lpush(message_list_key, json.dumps(ai_message, ensure_ascii=False))
                
                # 更新会话信息
                session_key = f"boss:chat:session:{userid}:{session_id}"
                client.hset(session_key, "last_message", ai_reply[:20])
                client.hset(session_key, "create_time", datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
                
                # 获取最新消息列表
                new_messages = []
                for msg in client.lrange(message_list_key, 0, -1):
                    try:
                        if isinstance(msg, bytes):
                            msg = msg.decode('utf-8', errors='ignore')
                        elif isinstance(msg, str):
                            msg = msg.encode('utf-8', errors='ignore').decode('utf-8')
                        new_messages.append(json.loads(msg))
                    except (json.JSONDecodeError, UnicodeDecodeError):
                        continue
                new_messages.reverse()
                
                return Response({
                    "code": 1,
                    "message": "获取回复成功",
                    "data": {
                        "reply": ai_reply,
                        "messages": new_messages[1:],
                        "session_id": session_id,
                        "job_recommend": True
                    }
                })

            # 获取消息列表，处理编码问题
            messages = []
            for msg in client.lrange(message_list_key, 0, -1):
                try:
                    if isinstance(msg, bytes):
                        msg = msg.decode('utf-8', errors='ignore')
                    elif isinstance(msg, str):
                        # 如果已经是字符串，确保它是UTF-8编码
                        msg = msg.encode('utf-8', errors='ignore').decode('utf-8')
                    messages.append(json.loads(msg))
                except (json.JSONDecodeError, UnicodeDecodeError):
                    continue
            print(f"messages的类型:{type(messages)}")
            for message in messages:
                print(f"从redis中获取的消息:{message}")
                print(f"从redis中获取的消息🉐️类型:{type(message)}")

            messages.reverse()
            print(f"从redis中获取10条消息:{messages}")
            last_message = compress_message_history(messages)
            print(f"最后完整的消息列表:{last_message}")
            my_message = last_message + [{"role": "user", "content": question}]
            logger.info(f"大模型输入的提示词:{my_message}")
            result = ai_client.chat.completions.create(
                model="qwen-plus",
                messages=my_message,
                stream=False,
                temperature=0.7,
            )
            ai_reply = result.choices[0].message.content
            # 确保AI回复使用UTF-8编码，避免emoji字符导致的编码问题
            if ai_reply:
                ai_reply = ai_reply.encode('utf-8', errors='ignore').decode('utf-8')
            print(f"大模型输出的回复:{ai_reply}")
            print(type(ai_reply))
            # logger.info(f"大模型输出的回复:{ai_reply}")
            # logger.info(f"大模型输出的回复--类型:{type(ai_reply)}")
            if intent_recognition_res == "generate_resume":
                # logger.info(f"大模型输出的简历信息:{ai_reply}")
                # ai_reply 是json格式的简历信息,转化成word
                # 生成word, 上传到文件服务器(本地),最后要URL
                # 把URL存到redis
                # 清理AI回复，提取JSON部分
                ai_reply = ai_reply.strip("```json").strip("```")

                # 尝试解析JSON，处理可能的格式问题
                try:
                    resume_info = json.loads(ai_reply)
                except json.JSONDecodeError as e:
                    print(f"JSON解析失败: {e}")
                    print(f"原始AI回复: {ai_reply}")

                    # 尝试多种方法修复JSON
                    json_str = ai_reply

                    # 方法1: 提取第一个完整的JSON对象
                    import re
                    json_match = re.search(r'\{.*\}', ai_reply, re.DOTALL)
                    if json_match:
                        json_str = json_match.group()

                    # 方法2: 修复常见的JSON格式问题
                    # 移除多余的右花括号
                    json_str = re.sub(r'\}\s*\}\s*$', '}', json_str)
                    # 移除末尾的逗号
                    json_str = re.sub(r',\s*\}', '}', json_str)
                    json_str = re.sub(r',\s*\]', ']', json_str)

                    try:
                        resume_info = json.loads(json_str)
                        print("成功修复并解析JSON")
                    except json.JSONDecodeError as e2:
                        print(f"修复后仍然无法解析: {e2}")
                        print(f"修复后的JSON: {json_str}")

                        # 方法3: 尝试找到最长的有效JSON
                        lines = json_str.split('\n')
                        for i in range(len(lines), 0, -1):
                            try:
                                partial_json = '\n'.join(lines[:i])
                                resume_info = json.loads(partial_json)
                                print(f"成功解析部分JSON，使用前{i}行")
                                break
                            except json.JSONDecodeError:
                                continue
                        else:
                            print("所有方法都失败，抛出原始错误")
                            raise e
                file_path = generate_word_resume(resume_info)
                logger.info(f"生成word文件成功:{file_path}")

                # 从文件路径中提取文件名
                resume_name = os.path.basename(file_path)
                file_path_url = f"{settings.DOMAIN}{settings.MEDIA_URL}{resume_name}"
                logger.info(f"file_path:{file_path_url}")
                ai_reply = "生成简历成功:" + f"<a href='{file_path_url}'>请查看</a>"

            ai_message = {"role": "assistant", "content": ai_reply}
            logger.info(f"生成word文件后大模型输出的回复:{ai_message}")
            # 4.2 添加消息到列表左侧
            client.lpush(message_list_key, json.dumps(ai_message, ensure_ascii=False))

            session_key = f"boss:chat:session:{userid}:{session_id}"
            client.hset(session_key, "last_message", ai_reply[:20])
            client.hset(session_key, "create_time", datetime.now().strftime("%Y-%m-%d %H:%M:%S"))

            # 获取最新消息列表，处理编码问题
            new_messages = []
            for msg in client.lrange(message_list_key, 0, -1):
                try:
                    if isinstance(msg, bytes):
                        msg = msg.decode('utf-8', errors='ignore')
                    elif isinstance(msg, str):
                        # 如果已经是字符串，确保它是UTF-8编码
                        msg = msg.encode('utf-8', errors='ignore').decode('utf-8')
                    new_messages.append(json.loads(msg))
                except (json.JSONDecodeError, UnicodeDecodeError):
                    continue
            new_messages.reverse()
            return Response({
                "code": 1,
                "message": "获取回复成功",
                "data": {
                    "reply": ai_reply,
                    "messages": new_messages[1:],
                    "session_id": session_id
                }
            })
        except Exception as e:
            print(e)
            error_msg = safe_encode_error_message(e)
            return Response({
                "code": 0,
                "message": f"获取回复失败:{error_msg}"
            })


